﻿using Infrastructure.Extension;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Serilog;
using System.Diagnostics;

namespace Infrastructure.WebApi.Middleware
{
    /// <summary>
    /// 请求日志
    /// </summary>
    public class RequestLogMiddleware
    {
        private readonly RequestDelegate next;
        public RequestLogMiddleware(RequestDelegate next) { this.next = next; }
        public async Task Invoke(HttpContext context)
        {
            var responseLog = new HttpLogInfo
            {
                Url = context.Request.GetAbsoluteUri(),
                Action = context.Request.Path,
                HttpMethod = context.Request.Method,
                Tag = LogTag.RequestLog.ToString(),
                UserIp = context.GetUserIp()
            };
            _Timer(context, responseLog);
            Stream responseBodyStream = context.Response.Body;
            var requestBody = string.Empty;
            try
            {
                using (var memStream = new MemoryStream())
                {
                    #region 特性判断
                    var endpoint = context.Features.Get<IEndpointFeature>()?.Endpoint;// request pipeline 中，保证 app.UseRouting() 在前
                    if (endpoint != null)
                    {
                        var actionAttribute = endpoint.Metadata.GetMetadata<TagAttribute>();
                        if (actionAttribute != null)
                        {

                        }
                    }
                    #endregion

                    #region 请求
                    if (Convert.ToBoolean((context.Request?.ContentType?.Contains("application/json"))))
                    {
                        context.Request.EnableBuffering();
                        var requestReader = new StreamReader(context.Request.Body);
                        var requestStr = await requestReader.ReadToEndAsync();
                        responseLog.RequestBody = requestStr.Substring(0, requestStr.Length <= 1000 ? requestStr.Length : 1000);
                        context.Request.Body.Position = 0;
                    }
                    #endregion
                    context.Response.Body = memStream;
                    await next(context);
                    #region 返回
                    memStream.Position = 0;
                    string responseBody = new StreamReader(memStream).ReadToEnd();
                    responseLog.ResponseBody = responseBody.Substring(0, responseBody.Length <= 200 ? responseBody.Length : 200);
                    #endregion
                    memStream.Position = 0;
                    await memStream.CopyToAsync(responseBodyStream);
                }
            }
            finally
            {
                context.Response.Body = responseBodyStream;
            }
        }
        private void _Timer(HttpContext context, HttpLogInfo log)
        {
            var watch = new Stopwatch();
            watch.Start();
            context.Response.OnCompleted(() =>
            {
                watch.Stop();
                var responseTime = watch.ElapsedMilliseconds;
                log.Time = responseTime;
                Log.Information("{url}{action}{method}{request}{response}{time_ms}{tag}{userip}", log.Url, log.Action, log.HttpMethod, log.RequestBody, log.ResponseBody, log.Time, log.Tag, log.UserIp);
                return Task.CompletedTask;
            });
        }
    }

}
